/****************************************************************** 
 ** Optimized 32-bit Twister ANSI C source code 
 ** 
 ** Author: Christian Forler <c.forler@sirrix.com>, 2008 
 ** 
 ** This algorithm and source code is released into the public domain. 
 ** 
 *******************************************************************/ 

#include <string.h> 
#include <stdio.h> 
#include <stdlib.h> 

#ifdef __GNUC_ 
#include <stdint.h> 
#endif 

#include "twister.h" 
#include "twister_tables.h" 
#include "speed_test.h" 

#define ALGORITHM_NAME "twister" 
#define	MAX_MARKER_LEN		50 
#define	SUBMITTER_INFO_LEN	128 

#define DATA_BLOCKSIZE       512 
#define DATA_BLOCKSIZE_BYTES  64 

#define DATA_OUTPUT_BLOCKSIZE 32 

/* Message and output block size in bytes for input/output message round */ 
#define BLOCKSIZE      64 
#define BLOCKSIZE_BITS  6 

/* Length of the state in bytes */ 
#define STATE_BYTELEN 64 

/***************************************************************************/ 

/*  Initiate Twister */ 
HashReturn Init(hashState *state, int hashbitlen) { 
  if ((hashbitlen>DATA_BLOCKSIZE || hashbitlen <DATA_OUTPUT_BLOCKSIZE) 
      || (hashbitlen%DATA_OUTPUT_BLOCKSIZE)) 
    return BAD_HASHBITLEN; 
  else { 
    /* Set ever state attribut to zero */ 
    memset(state, 0x0 ,sizeof(hashState)); 
    
    state->hs_counter=0xffffffffffffffffll; 
    state->hs_s[7]=(uint64_t)hashbitlen<<48; 
    state->hs_hashbitlen=hashbitlen; 
    return SUCCESS; 
  } 
} 

/***************************************************************************/ 

HashReturn Update(hashState *state, const BitSequence *data, 
                  DataLength databitlen) 
{ 

  
  /* Are there any unprocessed byte left */ 
  if(state->hs_databitlen) 
    { 
      if(state->hs_databitlen&7) return FAIL; 
      else 
	{ 
	  unsigned long int t = (unsigned long int) MIN(DATA_BLOCKSIZE-state->hs_databitlen, databitlen); 
	  unsigned long int p = (t&7) ? 1:0; 
	  
	  p+=t>>3; 
	  /* Intermediate data block with length that are not divisible by 8 */ 
	  memcpy(state->hs_data+(state->hs_databitlen>>3),data,p); 

#ifdef DEBUG 
	  { 
	    unsigned int i; 
	    printf("\np= %d\n",p); 
	    printf("hs_databitlen(%d)+t(%d) : %d\n",state->hs_databitlen,t, 
		   state->hs_databitlen+t); 
	    for(i=0;i<(p+(state->hs_databitlen>>3));i++) 
	      printf("0x%02x ",state->hs_data[i]); 
	    puts(""); 
	  } 
#endif 
	  
	  state->hs_databitlen+=t; 
	  if(state->hs_databitlen==DATA_BLOCKSIZE) 
	    { 
	      twist(state, (uint64_t *) state->hs_data); 
	      state->hs_databitlen=0; 
	      databitlen-=t;	 
	    } 
	  else { 
	    return SUCCESS; 
	  } 
	} 
    } 

  while(databitlen>=DATA_BLOCKSIZE) 
    { 
      twist(state, (uint64_t *) data); 
      data+=DATA_BLOCKSIZE_BYTES; 
      databitlen-=DATA_BLOCKSIZE; 
    } 

  
  if(databitlen) 
    { 
      unsigned long int p = (databitlen&7) ? 1:0; 
      p+=(unsigned long int) databitlen>>3; 
      memcpy(state->hs_data,data,p); 
      state->hs_databitlen+=databitlen; 
    }    

  
  
  return SUCCESS; 
} 


/***************************************************************************/ 

HashReturn Final(hashState *state, BitSequence *hashval) 
{ 
  DataLength ml= state->hs_cmesglen+state->hs_databitlen; 
 
  if(state->hs_databitlen) 
    { 
      unsigned long int i = state->hs_databitlen>>3; 
      unsigned long int r = state->hs_databitlen&7; 

#ifdef DEBUG 
      { 
	int j; 
	puts("Unpadded  Message:"); 
	for(j=0;j<=i;j++) printf("0x%02x ",state->hs_data[j]); 
	puts(""); 
      } 
#endif     

      state->hs_data[i]&=0xFF<<(8-r); 
      state->hs_data[i]|=1<<(7-r); 
      i+=1; 
      memset(state->hs_data+i,0,DATA_BLOCKSIZE_BYTES-i); 

#ifdef DEBUG 
      puts("Padded  Message:"); 
      for(r=0;r<i;r++) printf("0x%02x ",state->hs_data[r]); 
      puts(""); 
#endif 
    } 
  else 
    { 
      memset(state->hs_data,0,DATA_BLOCKSIZE_BYTES); 
      state->hs_data[0]=0x80; 
    } 

  twist(state,(uint64_t *) state->hs_data); 
  

  /* message length */ 
  state->hs_s[0]^=(uint8_t) (ml>>56); 
  state->hs_s[1]^=(uint8_t) (ml>>48); 
  state->hs_s[2]^=(uint8_t) (ml>>40); 
  state->hs_s[3]^=(uint8_t) (ml>>32); 
  state->hs_s[4]^=(uint8_t) (ml>>24); 
  state->hs_s[5]^=(uint8_t) (ml>>16); 
  state->hs_s[6]^=(uint8_t) (ml>>8);  
  state->hs_s[7]^=(uint8_t) (ml); 
  twister_mini_round(state); 

    if(state->hs_hashbitlen<=256) 
    { 
     twister_mini_round(state); 
    } 
  else 
    { 
      uint64_t ff[ROWS]; 

      ff[7]=state->hs_s[7]; 
      ff[6]=state->hs_s[6]; 
      ff[5]=state->hs_s[5]; 
      ff[4]=state->hs_s[4]; 
      ff[3]=state->hs_s[3]; 
      ff[2]=state->hs_s[2]; 
      ff[1]=state->hs_s[1]; 
      ff[0]=state->hs_s[0]; 
      state->hs_s[0]^=(uint8_t) (state->hs_ck0>>56); 
      state->hs_s[1]^=(uint8_t) (state->hs_ck0>>48); 
      state->hs_s[2]^=(uint8_t) (state->hs_ck0>>40); 
      state->hs_s[3]^=(uint8_t) (state->hs_ck0>>32); 
      state->hs_s[4]^=(uint8_t) (state->hs_ck0>>24); 
      state->hs_s[5]^=(uint8_t) (state->hs_ck0>>16); 
      state->hs_s[6]^=(uint8_t) (state->hs_ck0>>8); 
      state->hs_s[7]^=(uint8_t) (state->hs_ck0); 
      twister_mini_round(state); 

      state->hs_s[0]^=(uint8_t) (state->hs_ck1>>56); 
      state->hs_s[1]^=(uint8_t) (state->hs_ck1>>48); 
      state->hs_s[2]^=(uint8_t) (state->hs_ck1>>40); 
      state->hs_s[3]^=(uint8_t) (state->hs_ck1>>32); 
      state->hs_s[4]^=(uint8_t) (state->hs_ck1>>24); 
      state->hs_s[5]^=(uint8_t) (state->hs_ck1>>16); 
      state->hs_s[6]^=(uint8_t) (state->hs_ck1>>8); 
      state->hs_s[7]^=(uint8_t) (state->hs_ck1); 
      twister_mini_round(state); 

      state->hs_s[0]^=(uint8_t) (state->hs_ck2>>56); 
      state->hs_s[1]^=(uint8_t) (state->hs_ck2>>48); 
      state->hs_s[2]^=(uint8_t) (state->hs_ck2>>40); 
      state->hs_s[3]^=(uint8_t) (state->hs_ck2>>32); 
      state->hs_s[4]^=(uint8_t) (state->hs_ck2>>24); 
      state->hs_s[5]^=(uint8_t) (state->hs_ck2>>16); 
      state->hs_s[6]^=(uint8_t) (state->hs_ck2>>8); 
      state->hs_s[7]^=(uint8_t) (state->hs_ck2); 
      twister_mini_round(state); 
      state->hs_s[7]^=ff[7];   
      state->hs_s[6]^=ff[6]; 
      state->hs_s[5]^=ff[5]; 
      state->hs_s[4]^=ff[4]; 
      state->hs_s[3]^=ff[3]; 
      state->hs_s[2]^=ff[2]; 
      state->hs_s[1]^=ff[1]; 
      state->hs_s[0]^=ff[0]; 


      ff[7]=state->hs_s[7]; 
      ff[6]=state->hs_s[6]; 
      ff[5]=state->hs_s[5]; 
      ff[4]=state->hs_s[4]; 
      ff[3]=state->hs_s[3]; 
      ff[2]=state->hs_s[2]; 
      ff[1]=state->hs_s[1]; 
      ff[0]=state->hs_s[0]; 
      state->hs_s[0]^=(uint8_t) (state->hs_ck3>>56); 
      state->hs_s[1]^=(uint8_t) (state->hs_ck3>>48); 
      state->hs_s[2]^=(uint8_t) (state->hs_ck3>>40); 
      state->hs_s[3]^=(uint8_t) (state->hs_ck3>>32); 
      state->hs_s[4]^=(uint8_t) (state->hs_ck3>>24); 
      state->hs_s[5]^=(uint8_t) (state->hs_ck3>>16); 
      state->hs_s[6]^=(uint8_t) (state->hs_ck3>>8); 
      state->hs_s[7]^=(uint8_t) (state->hs_ck3); 
      twister_mini_round(state); 

      state->hs_s[0]^=(uint8_t) (state->hs_ck4>>56); 
      state->hs_s[1]^=(uint8_t) (state->hs_ck4>>48); 
      state->hs_s[2]^=(uint8_t) (state->hs_ck4>>40); 
      state->hs_s[3]^=(uint8_t) (state->hs_ck4>>32); 
      state->hs_s[4]^=(uint8_t) (state->hs_ck4>>24); 
      state->hs_s[5]^=(uint8_t) (state->hs_ck4>>16); 
      state->hs_s[6]^=(uint8_t) (state->hs_ck4>>8); 
      state->hs_s[7]^=(uint8_t) (state->hs_ck4); 
      twister_mini_round(state); 

      state->hs_s[0]^=(uint8_t) (state->hs_ck5>>56); 
      state->hs_s[1]^=(uint8_t) (state->hs_ck5>>48); 
      state->hs_s[2]^=(uint8_t) (state->hs_ck5>>40); 
      state->hs_s[3]^=(uint8_t) (state->hs_ck5>>32); 
      state->hs_s[4]^=(uint8_t) (state->hs_ck5>>24); 
      state->hs_s[5]^=(uint8_t) (state->hs_ck5>>16); 
      state->hs_s[6]^=(uint8_t) (state->hs_ck5>>8); 
      state->hs_s[7]^=(uint8_t) (state->hs_ck5); 
      twister_mini_round(state); 
      state->hs_s[7]^=ff[7]; 
      state->hs_s[6]^=ff[6]; 
      state->hs_s[5]^=ff[5]; 
      state->hs_s[4]^=ff[4]; 
      state->hs_s[3]^=ff[3]; 
      state->hs_s[2]^=ff[2]; 
      state->hs_s[1]^=ff[1]; 
      state->hs_s[0]^=ff[0]; 


      ff[7]=state->hs_s[7]; 
      ff[6]=state->hs_s[6]; 
      ff[5]=state->hs_s[5]; 
      ff[4]=state->hs_s[4]; 
      ff[3]=state->hs_s[3]; 
      ff[2]=state->hs_s[2]; 
      ff[1]=state->hs_s[1]; 
      ff[0]=state->hs_s[0]; 
      state->hs_s[0]^=(uint8_t) (state->hs_ck6>>56); 
      state->hs_s[1]^=(uint8_t) (state->hs_ck6>>48); 
      state->hs_s[2]^=(uint8_t) (state->hs_ck6>>40); 
      state->hs_s[3]^=(uint8_t) (state->hs_ck6>>32); 
      state->hs_s[4]^=(uint8_t) (state->hs_ck6>>24); 
      state->hs_s[5]^=(uint8_t) (state->hs_ck6>>16); 
      state->hs_s[6]^=(uint8_t) (state->hs_ck6>>8); 
      state->hs_s[7]^=(uint8_t) (state->hs_ck6); 
      twister_mini_round(state); 


      state->hs_s[0]^=(uint8_t) (state->hs_ck7>>56); 
      state->hs_s[1]^=(uint8_t) (state->hs_ck7>>48); 
      state->hs_s[2]^=(uint8_t) (state->hs_ck7>>40); 
      state->hs_s[3]^=(uint8_t) (state->hs_ck7>>32); 
      state->hs_s[4]^=(uint8_t) (state->hs_ck7>>24); 
      state->hs_s[5]^=(uint8_t) (state->hs_ck7>>16); 
      state->hs_s[6]^=(uint8_t) (state->hs_ck7>>8); 
      state->hs_s[7]^=(uint8_t) (state->hs_ck7); 
      twister_mini_round(state); 

      twister_mini_round(state); 
      state->hs_s[7]^=ff[7];   
      state->hs_s[6]^=ff[6]; 
      state->hs_s[5]^=ff[5]; 
      state->hs_s[4]^=ff[4]; 
      state->hs_s[3]^=ff[3]; 
      state->hs_s[2]^=ff[2]; 
      state->hs_s[1]^=ff[1]; 
      state->hs_s[0]^=ff[0]; 
    } 

  /* Output */ 
  twister_output(state, (uint64_t *) hashval); 

  return SUCCESS; 
} 

/***************************************************************************/ 

HashReturn Hash(int hashbitlen, const BitSequence *data, 
		DataLength databitlen, BitSequence *hashval) 
{ 
  hashState state; 
  int i; 

  if((i=Init(&state,hashbitlen))) return i; 
  if((i=Update(&state,data,databitlen))) return i; 
  Final(&state,hashval); 
 
  return SUCCESS; 
} 


/***************************************************************************/ 

void twist(hashState *state, uint64_t *data) 
{ 
uint64_t ff[ROWS]; 
  if(state->hs_hashbitlen<=256) 
    { 
      /* Twister<=256 */ 

      /* 1st maxi round */ 
      ff[7]=state->hs_s[7]; 
      ff[6]=state->hs_s[6]; 
      ff[5]=state->hs_s[5]; 
      ff[4]=state->hs_s[4]; 
      ff[3]=state->hs_s[3]; 
      ff[2]=state->hs_s[2]; 
      ff[1]=state->hs_s[1]; 
      ff[0]=state->hs_s[0]; 

      state->hs_s[0]^= (uint8_t) (*data>>56); 
      state->hs_s[1]^= (uint8_t) (*data>>48); 
      state->hs_s[2]^= (uint8_t) (*data>>40); 
      state->hs_s[3]^= (uint8_t) (*data>>32); 
      state->hs_s[4]^= (uint8_t) (*data>>24); 
      state->hs_s[5]^= (uint8_t) (*data>>16); 
      state->hs_s[6]^= (uint8_t) (*data>>8); 
      state->hs_s[7]^= (uint8_t) (*data++); 
      twister_mini_round(state); 


      state->hs_s[0]^= (uint8_t) (*data>>56); 
      state->hs_s[1]^= (uint8_t) (*data>>48); 
      state->hs_s[2]^= (uint8_t) (*data>>40); 
      state->hs_s[3]^= (uint8_t) (*data>>32); 
      state->hs_s[4]^= (uint8_t) (*data>>24); 
      state->hs_s[5]^= (uint8_t) (*data>>16); 
      state->hs_s[6]^= (uint8_t) (*data>>8); 
      state->hs_s[7]^= (uint8_t) (*data++); 
      twister_mini_round(state); 

      state->hs_s[0]^= (uint8_t) (*data>>56); 
      state->hs_s[1]^= (uint8_t) (*data>>48); 
      state->hs_s[2]^= (uint8_t) (*data>>40); 
      state->hs_s[3]^= (uint8_t) (*data>>32); 
      state->hs_s[4]^= (uint8_t) (*data>>24); 
      state->hs_s[5]^= (uint8_t) (*data>>16); 
      state->hs_s[6]^= (uint8_t) (*data>>8); 
      state->hs_s[7]^= (uint8_t) (*data++); 
      twister_mini_round(state); 

      state->hs_s[7]^=ff[7];   
      state->hs_s[6]^=ff[6]; 
      state->hs_s[5]^=ff[5]; 
      state->hs_s[4]^=ff[4]; 
      state->hs_s[3]^=ff[3]; 
      state->hs_s[2]^=ff[2]; 
      state->hs_s[1]^=ff[1]; 
      state->hs_s[0]^=ff[0]; 


      /* 2nd maxi round */ 
      ff[7]=state->hs_s[7]; 
      ff[6]=state->hs_s[6]; 
      ff[5]=state->hs_s[5]; 
      ff[4]=state->hs_s[4]; 
      ff[3]=state->hs_s[3]; 
      ff[2]=state->hs_s[2]; 
      ff[1]=state->hs_s[1]; 
      ff[0]=state->hs_s[0]; 

      state->hs_s[0]^= (uint8_t) (*data>>56); 
      state->hs_s[1]^= (uint8_t) (*data>>48); 
      state->hs_s[2]^= (uint8_t) (*data>>40); 
      state->hs_s[3]^= (uint8_t) (*data>>32); 
      state->hs_s[4]^= (uint8_t) (*data>>24); 
      state->hs_s[5]^= (uint8_t) (*data>>16); 
      state->hs_s[6]^= (uint8_t) (*data>>8); 
      state->hs_s[7]^= (uint8_t) (*data++); 
      twister_mini_round(state); 

      state->hs_s[0]^= (uint8_t) (*data>>56); 
      state->hs_s[1]^= (uint8_t) (*data>>48); 
      state->hs_s[2]^= (uint8_t) (*data>>40); 
      state->hs_s[3]^= (uint8_t) (*data>>32); 
      state->hs_s[4]^= (uint8_t) (*data>>24); 
      state->hs_s[5]^= (uint8_t) (*data>>16); 
      state->hs_s[6]^= (uint8_t) (*data>>8); 
      state->hs_s[7]^= (uint8_t) (*data++); 
      twister_mini_round(state); 

      state->hs_s[0]^= (uint8_t) (*data>>56); 
      state->hs_s[1]^= (uint8_t) (*data>>48); 
      state->hs_s[2]^= (uint8_t) (*data>>40); 
      state->hs_s[3]^= (uint8_t) (*data>>32); 
      state->hs_s[4]^= (uint8_t) (*data>>24); 
      state->hs_s[5]^= (uint8_t) (*data>>16); 
      state->hs_s[6]^= (uint8_t) (*data>>8); 
      state->hs_s[7]^= (uint8_t) (*data++); 
      twister_mini_round(state); 

      state->hs_s[7]^=ff[7]; 
      state->hs_s[6]^=ff[6]; 
      state->hs_s[5]^=ff[5]; 
      state->hs_s[4]^=ff[4]; 
      state->hs_s[3]^=ff[3]; 
      state->hs_s[2]^=ff[2]; 
      state->hs_s[1]^=ff[1]; 
      state->hs_s[0]^=ff[0]; 


      /* 3rd maxi round */ 
      ff[7]=state->hs_s[7]; 
      ff[6]=state->hs_s[6]; 
      ff[5]=state->hs_s[5]; 
      ff[4]=state->hs_s[4]; 
      ff[3]=state->hs_s[3]; 
      ff[2]=state->hs_s[2]; 
      ff[1]=state->hs_s[1]; 
      ff[0]=state->hs_s[0]; 

      state->hs_s[0]^= (uint8_t) (*data>>56); 
      state->hs_s[1]^= (uint8_t) (*data>>48); 
      state->hs_s[2]^= (uint8_t) (*data>>40); 
      state->hs_s[3]^= (uint8_t) (*data>>32); 
      state->hs_s[4]^= (uint8_t) (*data>>24); 
      state->hs_s[5]^= (uint8_t) (*data>>16); 
      state->hs_s[6]^= (uint8_t) (*data>>8); 
      state->hs_s[7]^= (uint8_t) (*data++); 
      twister_mini_round(state); 

      state->hs_s[0]^= (uint8_t) (*data>>56); 
      state->hs_s[1]^= (uint8_t) (*data>>48); 
      state->hs_s[2]^= (uint8_t) (*data>>40); 
      state->hs_s[3]^= (uint8_t) (*data>>32); 
      state->hs_s[4]^= (uint8_t) (*data>>24); 
      state->hs_s[5]^= (uint8_t) (*data>>16); 
      state->hs_s[6]^= (uint8_t) (*data>>8); 
      state->hs_s[7]^= (uint8_t) (*data++); 
      twister_mini_round(state); 

      twister_mini_round(state); 

      state->hs_s[7]^=ff[7]; 
      state->hs_s[6]^=ff[6]; 
      state->hs_s[5]^=ff[5]; 
      state->hs_s[4]^=ff[4]; 
      state->hs_s[3]^=ff[3]; 
      state->hs_s[2]^=ff[2]; 
      state->hs_s[1]^=ff[1]; 
      state->hs_s[0]^=ff[0]; 

    } 
  /* Twister>256 */ 
  else 
    { 
      /* 1st maxi round */ 
      ff[7]=state->hs_s[7]; 
      ff[6]=state->hs_s[6]; 
      ff[5]=state->hs_s[5]; 
      ff[4]=state->hs_s[4]; 
      ff[3]=state->hs_s[3]; 
      ff[2]=state->hs_s[2]; 
      ff[1]=state->hs_s[1]; 
      ff[0]=state->hs_s[0]; 

      state->hs_ck0^=state->hs_s[0]+state->hs_ck1; 
      state->hs_s[0]^= (uint8_t) (*data>>56); 
      state->hs_s[1]^= (uint8_t) (*data>>48); 
      state->hs_s[2]^= (uint8_t) (*data>>40); 
      state->hs_s[3]^= (uint8_t) (*data>>32); 
      state->hs_s[4]^= (uint8_t) (*data>>24); 
      state->hs_s[5]^= (uint8_t) (*data>>16); 
      state->hs_s[6]^= (uint8_t) (*data>>8); 
      state->hs_s[7]^= (uint8_t) (*data++); 
      twister_mini_round(state); 

      state->hs_ck1^=state->hs_s[0]+state->hs_ck2; 
      state->hs_s[0]^= (uint8_t) (*data>>56); 
      state->hs_s[1]^= (uint8_t) (*data>>48); 
      state->hs_s[2]^= (uint8_t) (*data>>40); 
      state->hs_s[3]^= (uint8_t) (*data>>32); 
      state->hs_s[4]^= (uint8_t) (*data>>24); 
      state->hs_s[5]^= (uint8_t) (*data>>16); 
      state->hs_s[6]^= (uint8_t) (*data>>8); 
      state->hs_s[7]^= (uint8_t) (*data++); 
      twister_mini_round(state); 

      state->hs_ck2^=state->hs_s[0]+state->hs_ck3; 
      state->hs_s[0]^= (uint8_t) (*data>>56); 
      state->hs_s[1]^= (uint8_t) (*data>>48); 
      state->hs_s[2]^= (uint8_t) (*data>>40); 
      state->hs_s[3]^= (uint8_t) (*data>>32); 
      state->hs_s[4]^= (uint8_t) (*data>>24); 
      state->hs_s[5]^= (uint8_t) (*data>>16); 
      state->hs_s[6]^= (uint8_t) (*data>>8); 
      state->hs_s[7]^= (uint8_t) (*data++); 
      twister_mini_round(state); 

      state->hs_s[7]^=ff[7]; 
      state->hs_s[6]^=ff[6]; 
      state->hs_s[5]^=ff[5]; 
      state->hs_s[4]^=ff[4]; 
      state->hs_s[3]^=ff[3]; 
      state->hs_s[2]^=ff[2]; 
      state->hs_s[1]^=ff[1]; 
      state->hs_s[0]^=ff[0]; 

      /* 2nd maxi round */ 
      ff[7]=state->hs_s[7]; 
      ff[6]=state->hs_s[6]; 
      ff[5]=state->hs_s[5]; 
      ff[4]=state->hs_s[4]; 
      ff[3]=state->hs_s[3]; 
      ff[2]=state->hs_s[2]; 
      ff[1]=state->hs_s[1]; 
      ff[0]=state->hs_s[0]; 

      state->hs_ck3^=state->hs_s[0]+state->hs_ck4; 
      state->hs_s[0]^= (uint8_t) (*data>>56); 
      state->hs_s[1]^= (uint8_t) (*data>>48); 
      state->hs_s[2]^= (uint8_t) (*data>>40); 
      state->hs_s[3]^= (uint8_t) (*data>>32); 
      state->hs_s[4]^= (uint8_t) (*data>>24); 
      state->hs_s[5]^= (uint8_t) (*data>>16); 
      state->hs_s[6]^= (uint8_t) (*data>>8); 
      state->hs_s[7]^= (uint8_t) (*data++); 
      twister_mini_round(state); 

      /* Blank round */ 
      twister_mini_round(state); 

      state->hs_ck4^=state->hs_s[0]+state->hs_ck5; 
      state->hs_s[0]^= (uint8_t) (*data>>56); 
      state->hs_s[1]^= (uint8_t) (*data>>48); 
      state->hs_s[2]^= (uint8_t) (*data>>40); 
      state->hs_s[3]^= (uint8_t) (*data>>32); 
      state->hs_s[4]^= (uint8_t) (*data>>24); 
      state->hs_s[5]^= (uint8_t) (*data>>16); 
      state->hs_s[6]^= (uint8_t) (*data>>8); 
      state->hs_s[7]^= (uint8_t) (*data++); 
      twister_mini_round(state); 

      state->hs_s[7]^=ff[7]; 
      state->hs_s[6]^=ff[6]; 
      state->hs_s[5]^=ff[5]; 
      state->hs_s[4]^=ff[4]; 
      state->hs_s[3]^=ff[3]; 
      state->hs_s[2]^=ff[2]; 
      state->hs_s[1]^=ff[1]; 
      state->hs_s[0]^=ff[0]; 

      /* 3rd maxi round */ 
      ff[7]=state->hs_s[7]; 
      ff[6]=state->hs_s[6]; 
      ff[5]=state->hs_s[5]; 
      ff[4]=state->hs_s[4]; 
      ff[3]=state->hs_s[3]; 
      ff[2]=state->hs_s[2]; 
      ff[1]=state->hs_s[1]; 
      ff[0]=state->hs_s[0]; 

      state->hs_ck5^=state->hs_s[0]+state->hs_ck6; 
      state->hs_s[0]^= (uint8_t) (*data>>56); 
      state->hs_s[1]^= (uint8_t) (*data>>48); 
      state->hs_s[2]^= (uint8_t) (*data>>40); 
      state->hs_s[3]^= (uint8_t) (*data>>32); 
      state->hs_s[4]^= (uint8_t) (*data>>24); 
      state->hs_s[5]^= (uint8_t) (*data>>16); 
      state->hs_s[6]^= (uint8_t) (*data>>8); 
      state->hs_s[7]^= (uint8_t) (*data++); 
      twister_mini_round(state); 

      state->hs_ck6^=state->hs_s[0]+state->hs_ck7; 
      state->hs_s[0]^= (uint8_t) (*data>>56); 
      state->hs_s[1]^= (uint8_t) (*data>>48); 
      state->hs_s[2]^= (uint8_t) (*data>>40); 
      state->hs_s[3]^= (uint8_t) (*data>>32); 
      state->hs_s[4]^= (uint8_t) (*data>>24); 
      state->hs_s[5]^= (uint8_t) (*data>>16); 
      state->hs_s[6]^= (uint8_t) (*data>>8); 
      state->hs_s[7]^= (uint8_t) (*data++); 
      twister_mini_round(state); 

      state->hs_ck7^=state->hs_s[0]+state->hs_ck0; 
      state->hs_s[0]^= (uint8_t) (*data>>56); 
      state->hs_s[1]^= (uint8_t) (*data>>48); 
      state->hs_s[2]^= (uint8_t) (*data>>40); 
      state->hs_s[3]^= (uint8_t) (*data>>32); 
      state->hs_s[4]^= (uint8_t) (*data>>24); 
      state->hs_s[5]^= (uint8_t) (*data>>16); 
      state->hs_s[6]^= (uint8_t) (*data>>8); 
      state->hs_s[7]^= (uint8_t) (*data++); 
      twister_mini_round(state); 

      /* Blank round */ 
      twister_mini_round(state); 

      state->hs_s[7]^=ff[7]; 
      state->hs_s[6]^=ff[6]; 
      state->hs_s[5]^=ff[5]; 
      state->hs_s[4]^=ff[4]; 
      state->hs_s[3]^=ff[3]; 
      state->hs_s[2]^=ff[2]; 
      state->hs_s[1]^=ff[1]; 
      state->hs_s[0]^=ff[0]; 
    } 
  state->hs_cmesglen+=512; 
} 

/***************************************************************************/ 

void twister_mini_round(hashState *state) 
{ 
uint64_t p0; 
  uint64_t p1; 
  uint64_t p2; 
  uint64_t p3; 
  uint64_t p4; 
  uint64_t p5; 
  uint64_t p6; 
  uint64_t p7; 


  /* Add inverted twist counter */ 
  state->hs_s[1]^= state->hs_counter--; 

  p0= t0[(uint8_t) (state->hs_s[0]>>56)]; 
  p7= t1[(uint8_t) (state->hs_s[0]>>48)]; 
  p6= t2[(uint8_t) (state->hs_s[0]>>40)]; 
  p5= t3[(uint8_t) (state->hs_s[0]>>32)]; 
  p4= t4[(uint8_t) (state->hs_s[0]>>24)]; 
  p3= t5[(uint8_t) (state->hs_s[0]>>16)]; 
  p2= t6[(uint8_t) (state->hs_s[0]>>8)]; 
  p1= t7[(uint8_t) (state->hs_s[0])]; 

  p1^= t0[(uint8_t) (state->hs_s[1]>>56)]; 
  p0^= t1[(uint8_t) (state->hs_s[1]>>48)]; 
  p7^= t2[(uint8_t) (state->hs_s[1]>>40)]; 
  p6^= t3[(uint8_t) (state->hs_s[1]>>32)]; 
  p5^= t4[(uint8_t) (state->hs_s[1]>>24)]; 
  p4^= t5[(uint8_t) (state->hs_s[1]>>16)]; 
  p3^= t6[(uint8_t) (state->hs_s[1]>>8)]; 
  p2^= t7[(uint8_t) (state->hs_s[1])]; 

  p2^= t0[(uint8_t) (state->hs_s[2]>>56)]; 
  p1^= t1[(uint8_t) (state->hs_s[2]>>48)]; 
  p0^= t2[(uint8_t) (state->hs_s[2]>>40)]; 
  p7^= t3[(uint8_t) (state->hs_s[2]>>32)]; 
  p6^= t4[(uint8_t) (state->hs_s[2]>>24)]; 
  p5^= t5[(uint8_t) (state->hs_s[2]>>16)]; 
  p4^= t6[(uint8_t) (state->hs_s[2]>>8)]; 
  p3^= t7[(uint8_t) (state->hs_s[2])]; 

  p3^= t0[(uint8_t) (state->hs_s[3]>>56)]; 
  p2^= t1[(uint8_t) (state->hs_s[3]>>48)]; 
  p1^= t2[(uint8_t) (state->hs_s[3]>>40)]; 
  p0^= t3[(uint8_t) (state->hs_s[3]>>32)]; 
  p7^= t4[(uint8_t) (state->hs_s[3]>>24)]; 
  p6^= t5[(uint8_t) (state->hs_s[3]>>16)]; 
  p5^= t6[(uint8_t) (state->hs_s[3]>>8)]; 
  p4^= t7[(uint8_t) (state->hs_s[3])]; 

  p4^= t0[(uint8_t) (state->hs_s[4]>>56)]; 
  p3^= t1[(uint8_t) (state->hs_s[4]>>48)]; 
  p2^= t2[(uint8_t) (state->hs_s[4]>>40)]; 
  p1^= t3[(uint8_t) (state->hs_s[4]>>32)]; 
  p0^= t4[(uint8_t) (state->hs_s[4]>>24)]; 
  p7^= t5[(uint8_t) (state->hs_s[4]>>16)]; 
  p6^= t6[(uint8_t) (state->hs_s[4]>>8)]; 
  p5^= t7[(uint8_t) (state->hs_s[4])]; 

  p5^= t0[(uint8_t) (state->hs_s[5]>>56)]; 
  p4^= t1[(uint8_t) (state->hs_s[5]>>48)]; 
  p3^= t2[(uint8_t) (state->hs_s[5]>>40)]; 
  p2^= t3[(uint8_t) (state->hs_s[5]>>32)]; 
  p1^= t4[(uint8_t) (state->hs_s[5]>>24)]; 
  p0^= t5[(uint8_t) (state->hs_s[5]>>16)]; 
  p7^= t6[(uint8_t) (state->hs_s[5]>>8)]; 
  p6^= t7[(uint8_t) (state->hs_s[5])]; 

  p6^= t0[(uint8_t) (state->hs_s[6]>>56)]; 
  p5^= t1[(uint8_t) (state->hs_s[6]>>48)]; 
  p4^= t2[(uint8_t) (state->hs_s[6]>>40)]; 
  p3^= t3[(uint8_t) (state->hs_s[6]>>32)]; 
  p2^= t4[(uint8_t) (state->hs_s[6]>>24)]; 
  p1^= t5[(uint8_t) (state->hs_s[6]>>16)]; 
  p0^= t6[(uint8_t) (state->hs_s[6]>>8)]; 
  p7^= t7[(uint8_t) (state->hs_s[6])]; 

  p7^= t0[(uint8_t) (state->hs_s[7]>>56)]; 
  p6^= t1[(uint8_t) (state->hs_s[7]>>48)]; 
  p5^= t2[(uint8_t) (state->hs_s[7]>>40)]; 
  p4^= t3[(uint8_t) (state->hs_s[7]>>32)]; 
  p3^= t4[(uint8_t) (state->hs_s[7]>>24)]; 
  p2^= t5[(uint8_t) (state->hs_s[7]>>16)]; 
  p1^= t6[(uint8_t) (state->hs_s[7]>>8)]; 
  p0^= t7[(uint8_t) (state->hs_s[7])]; 

  state->hs_s[0]=p0; 
  state->hs_s[1]=p1; 
  state->hs_s[2]=p2; 
  state->hs_s[3]=p3; 
  state->hs_s[4]=p4; 
  state->hs_s[5]=p5; 
  state->hs_s[6]=p6; 
  state->hs_s[7]=p7; 
} 

/***************************************************************************/ 

void twister_output(hashState *state, uint64_t *hashval) 
{ 
  int i; 
  int oblocks=state->hs_hashbitlen>>6; /* Number of 64-bit outbut blocks */ 
  uint64_t ff[ROWS]; 

  if(state->hs_hashbitlen%BLOCKSIZE) oblocks+=1; 

  for(i=0;i<oblocks;i++) 
    { 
      ff[0]=state->hs_s[0]; 
      ff[1]=state->hs_s[1]; 
      ff[2]=state->hs_s[2]; 
      ff[3]=state->hs_s[3]; 
      ff[4]=state->hs_s[4]; 
      ff[5]=state->hs_s[5]; 
      ff[6]=state->hs_s[6]; 
      ff[7]=state->hs_s[7]; 
      twister_mini_round(state); 
      state->hs_s[0]^=ff[0]; 
      state->hs_s[1]^=ff[1]; 
      state->hs_s[2]^=ff[2]; 
      state->hs_s[3]^=ff[3]; 
      state->hs_s[4]^=ff[4]; 
      state->hs_s[5]^=ff[5]; 
      state->hs_s[6]^=ff[6]; 
      state->hs_s[7]^=ff[7]; 
      twister_mini_round(state); 
      hashval[i]=state->hs_s[0]^ff[0]; 
    } 

} 
 

/***************************************************************************/ 

void print_state(hashState *state) 
{ 
  printf("%02llx %02llx %02llx %02llx %02llx %02llx %02llx %02llx\n", 
	 state->hs_s[0]>>56 & 0xFF, state->hs_s[1]>>56 & 0xFF, 
	 state->hs_s[2]>>56 & 0xFF, state->hs_s[3]>>56 & 0xFF, 
	 state->hs_s[4]>>56 & 0xFF, state->hs_s[5]>>56 & 0xFF, 
	 state->hs_s[6]>>56 & 0xFF, state->hs_s[7]>>56 & 0xFF); 

  printf("%02llx %02llx %02llx %02llx %02llx %02llx %02llx %02llx\n", 
	 state->hs_s[0]>>48 & 0xFF, state->hs_s[1]>>48 & 0xFF, 
	 state->hs_s[2]>>48 & 0xFF, state->hs_s[3]>>48 & 0xFF, 
	 state->hs_s[4]>>48 & 0xFF, state->hs_s[5]>>48 & 0xFF, 
	 state->hs_s[6]>>48 & 0xFF, state->hs_s[7]>>48 & 0xFF); 

  printf("%02llx %02llx %02llx %02llx %02llx %02llx %02llx %02llx\n", 
	 state->hs_s[0]>>40 & 0xFF, state->hs_s[1]>>40 & 0xFF, 
	 state->hs_s[2]>>40 & 0xFF, state->hs_s[3]>>40 & 0xFF, 
	 state->hs_s[4]>>40 & 0xFF, state->hs_s[5]>>40 & 0xFF, 
	 state->hs_s[6]>>40 & 0xFF, state->hs_s[7]>>40 & 0xFF); 

  printf("%02llx %02llx %02llx %02llx %02llx %02llx %02llx %02llx\n", 
	 state->hs_s[0]>>32 & 0xFF, state->hs_s[1]>>32 & 0xFF, 
	 state->hs_s[2]>>32 & 0xFF, state->hs_s[3]>>32 & 0xFF, 
	 state->hs_s[4]>>32 & 0xFF, state->hs_s[5]>>32 & 0xFF, 
	 state->hs_s[6]>>32 & 0xFF, state->hs_s[7]>>32 & 0xFF); 

  printf("%02llx %02llx %02llx %02llx %02llx %02llx %02llx %02llx\n", 
	 state->hs_s[0]>>24 & 0xFF, state->hs_s[1]>>24 & 0xFF, 
	 state->hs_s[2]>>24 & 0xFF, state->hs_s[3]>>24 & 0xFF, 
	 state->hs_s[4]>>24 & 0xFF, state->hs_s[5]>>24 & 0xFF, 
	 state->hs_s[6]>>24 & 0xFF, state->hs_s[7]>>24 & 0xFF); 

  printf("%02llx %02llx %02llx %02llx %02llx %02llx %02llx %02llx\n", 
	 state->hs_s[0]>>16 & 0xFF, state->hs_s[1]>>16 & 0xFF, 
	 state->hs_s[2]>>16 & 0xFF, state->hs_s[3]>>16 & 0xFF, 
	 state->hs_s[4]>>16 & 0xFF, state->hs_s[5]>>16 & 0xFF, 
	 state->hs_s[6]>>16 & 0xFF, state->hs_s[7]>>16 & 0xFF); 

  printf("%02llx %02llx %02llx %02llx %02llx %02llx %02llx %02llx\n", 
	 state->hs_s[0]>>8 & 0xFF, state->hs_s[1]>>8 & 0xFF, 
	 state->hs_s[2]>>8 & 0xFF, state->hs_s[3]>>8 & 0xFF, 
	 state->hs_s[4]>>8 & 0xFF, state->hs_s[5]>>8 & 0xFF, 
	 state->hs_s[6]>>8 & 0xFF, state->hs_s[7]>>8 & 0xFF); 

  printf("%02llx %02llx %02llx %02llx %02llx %02llx %02llx %02llx\n\n", 
	 state->hs_s[0] & 0xFF, state->hs_s[1] & 0xFF, 
	 state->hs_s[2] & 0xFF, state->hs_s[3] & 0xFF, 
	 state->hs_s[4] & 0xFF, state->hs_s[5] & 0xFF, 
	 state->hs_s[6] & 0xFF, state->hs_s[7] & 0xFF); 
} 


//////////////////////////////////////////////////////////////////////////////////// 
typedef enum { KAT_SUCCESS = 0, KAT_FILE_OPEN_ERROR = 1, KAT_HEADER_ERROR = 2, KAT_DATA_ERROR = 3, KAT_HASH_ERROR = 4 } STATUS_CODES; 

STATUS_CODES    genShortMsg(int hashbitlen); 
STATUS_CODES    genLongMsg(int hashbitlen); 
STATUS_CODES    genExtremelyLongMsg(int hashbitlen); 
STATUS_CODES    genMonteCarlo(int hashbitlen); 
int             FindMarker(FILE *infile, const char *marker); 
int             ReadHex(FILE *infile, BitSequence *A, int Length, char *str); 
void    fprintBstr(FILE *fp, char *S, BitSequence *A, int L); 

STATUS_CODES 
main() 
{ 
        int             i, ret_val,  bitlens[4] = { 224, 256, 384, 512 }; 
        unsigned long timeStart = clock(); 
        for ( i=0; i<4; i++ ) { 
                printf("%lums:\n\t", clock() - timeStart); 
                if ( (ret_val = genShortMsg(bitlens[i])) != KAT_SUCCESS ) 
                        return ret_val; 
                printf("%lums:\n\t", clock() - timeStart); 
                if ( (ret_val = genLongMsg(bitlens[i])) != KAT_SUCCESS ) 
                        return ret_val; 
                printf("%lums:\n\t", clock() - timeStart); 
                if ( (ret_val = genExtremelyLongMsg(bitlens[i])) != KAT_SUCCESS ) 
                        return ret_val; 
                printf("%lums:\n\t", clock() - timeStart); 
                if ( (ret_val = genMonteCarlo(bitlens[i])) != KAT_SUCCESS ) 
                        return ret_val; 
        } 
        printf("overall test time: %lums", clock() - timeStart); 
        return KAT_SUCCESS; 
} 

STATUS_CODES 
genShortMsg(int hashbitlen) 
{ 
        char            line[SUBMITTER_INFO_LEN]; 
        int                     msglen, msgbytelen, done; 
        BitSequence     Msg[256], MD[64]; 
        FILE            *fp_in; 
        char            logFileName [100]; 
        FILE            *logFile; 

        sprintf(logFileName, "%s_genShortMsg_%d.log", ALGORITHM_NAME, hashbitlen); 
        printf("logging results to: %s\n", logFileName); 
        logFile = fopen(logFileName, "w"); 
 
        if ( (fp_in = fopen("ShortMsgKAT.txt", "r")) == NULL ) { 
                printf("Couldn't open <ShortMsgKAT.txt> for read\n"); 
                return KAT_FILE_OPEN_ERROR; 
        } 

        if ( FindMarker(fp_in, "# Algorithm Name:") ) { 
                fscanf(fp_in, "%[^\n]\n", line); 
        } 
        else { 
                printf("genShortMsg: Couldn't read Algorithm Name\n"); 
                return KAT_HEADER_ERROR; 
        } 
        if ( FindMarker(fp_in, "# Principal Submitter:") ) { 
                fscanf(fp_in, "%[^\n]\n", line); 
        } 
        else { 
                printf("genShortMsg: Couldn't read Principal Submitter\n"); 
                return KAT_HEADER_ERROR; 
        } 

        done = 0; 
        timeTest(0, logFile);   //test start 
        do { 
                if ( FindMarker(fp_in, "Len = ") ) 
                        fscanf(fp_in, "%d", &msglen); 
                else { 
                        done = 1; 
                        break; 
                } 
                msgbytelen = (msglen+7)/8; 

                if ( !ReadHex(fp_in, Msg, msgbytelen, "Msg = ") ) { 
                        printf("ERROR: unable to read 'Msg' from <ShortMsgKAT.txt>\n"); 
                        return KAT_DATA_ERROR; 
                } 
                timeTest(1, logFile);   //unit test start 
                Hash(hashbitlen, Msg, msglen, MD); 
                timeTest(2, logFile);   //unit test stop 
        } while ( !done ); 
        timeTest(3, logFile);   //test stop 
        fclose(logFile); 
        printf("\tfinished ShortMsgKAT for <%d>\n", hashbitlen); 

        fclose(fp_in); 

        return KAT_SUCCESS; 
} 

STATUS_CODES 
genLongMsg(int hashbitlen) 
{ 
        char            line[SUBMITTER_INFO_LEN]; 
        int                     msglen, msgbytelen, done; 
        BitSequence     Msg[4288], MD[64]; 
        FILE            *fp_in; 
        char            logFileName [100]; 
        FILE            *logFile; 

        sprintf(logFileName, "%s_genLongMsg_%d.log", ALGORITHM_NAME, hashbitlen); 
        printf("logging results to: %s\n", logFileName); 
        logFile = fopen(logFileName, "w"); 

        if ( (fp_in = fopen("LongMsgKAT.txt", "r")) == NULL ) { 
                printf("Couldn't open <LongMsgKAT.txt> for read\n"); 
                return KAT_FILE_OPEN_ERROR; 
        } 

        if ( FindMarker(fp_in, "# Algorithm Name:") ) { 
                fscanf(fp_in, "%[^\n]\n", line); 
        } 
        else { 
                printf("genLongMsg: Couldn't read Algorithm Name\n"); 
                return KAT_HEADER_ERROR; 
        } 
        if ( FindMarker(fp_in, "# Principal Submitter:") ) { 
                fscanf(fp_in, "%[^\n]\n", line); 
        } 
        else { 
                printf("genLongMsg: Couldn't read Principal Submitter\n"); 
                return KAT_HEADER_ERROR; 
        } 

        done = 0; 
        timeTest(0, logFile);   //test start 
        do { 
                if ( FindMarker(fp_in, "Len = ") ) 
                        fscanf(fp_in, "%d", &msglen); 
                else 
                        break; 
                msgbytelen = (msglen+7)/8; 

                if ( !ReadHex(fp_in, Msg, msgbytelen, "Msg = ") ) { 
                        printf("ERROR: unable to read 'Msg' from <LongMsgKAT.txt>\n"); 
                        return KAT_DATA_ERROR; 
                } 
                timeTest(1, logFile);   //unit test start 
                Hash(hashbitlen, Msg, msglen, MD); 
                timeTest(2, logFile);   //unit test stop 
        } while ( !done ); 
        timeTest(3, logFile);   //test stop 
        fclose(logFile); 
        printf("\tfinished LongMsgKAT for <%d>\n", hashbitlen); 

        fclose(fp_in); 

        return KAT_SUCCESS; 
} 

STATUS_CODES 
genExtremelyLongMsg(int hashbitlen) 
{ 
        char            line[SUBMITTER_INFO_LEN]; 
        BitSequence     Text[65], MD[64]; 
        int                     i, repeat; 
        FILE            *fp_in; 
        hashState       state; 
        HashReturn      retval; 
        char            logFileName [100]; 
        FILE            *logFile; 

        sprintf(logFileName, "%s_genExtremelyLongMsg_%d.log", ALGORITHM_NAME, hashbitlen); 
        printf("logging results to: %s\n", logFileName); 
        logFile = fopen(logFileName, "w"); 

        if ( (fp_in = fopen("ExtremelyLongMsgKAT.txt", "r")) == NULL ) { 
                printf("Couldn't open <ExtremelyLongMsgKAT.txt> for read\n"); 
                return KAT_FILE_OPEN_ERROR; 
        } 

        if ( FindMarker(fp_in, "# Algorithm Name:") ) { 
                fscanf(fp_in, "%[^\n]\n", line); 
        } 
        else { 
                printf("genExtremelyLongMsg: Couldn't read Algorithm Name\n"); 
                return KAT_HEADER_ERROR; 
        } 
        if ( FindMarker(fp_in, "# Principal Submitter:") ) { 
                fscanf(fp_in, "%[^\n]\n", line); 
        } 
        else { 
                printf("genExtremelyLongMsg: Couldn't read Principal Submitter\n"); 
                return KAT_HEADER_ERROR; 
        } 


        if ( FindMarker(fp_in, "Repeat = ") ) 
                fscanf(fp_in, "%d", &repeat); 
        else { 
                printf("ERROR: unable to read 'Repeat' from <ExtremelyLongMsgKAT.txt>\n"); 
                return KAT_DATA_ERROR; 
        } 

        if ( FindMarker(fp_in, "Text = ") ) 
                fscanf(fp_in, "%s", Text); 
        else { 
                printf("ERROR: unable to read 'Text' from <ExtremelyLongMsgKAT.txt>\n"); 
                return KAT_DATA_ERROR; 
        } 

//      memcpy(Text, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno", 64); 
        timeTest(0, logFile);   //test start 
        timeTest(1, logFile);   //unit test start 
        if ( (retval = Init(&state, hashbitlen)) != KAT_SUCCESS ) { 
                printf("Init returned <%d> in genExtremelyLongMsg\n", retval); 
                return KAT_HASH_ERROR; 
        } 
        timeTest(2, logFile);   //unit test stop 
        for ( i=0; i<repeat; i++ ) 
        { 
                if (i % 8192 == 0) timeTest(1, logFile);        //unit test start 
                if ( (retval = Update(&state, Text, 512)) != KAT_SUCCESS ) { 
                        printf("Update returned <%d> in genExtremelyLongMsg\n", retval); 
                        return KAT_HASH_ERROR; 
                } 
                if (i % 8192 == 0) timeTest(2, logFile);        //unit test stop 
        } 
        timeTest(1, logFile);   //unit test start 
        if ( (retval = Final(&state, MD)) != KAT_SUCCESS ) { 
                printf("Final returned <%d> in genExtremelyLongMsg\n", retval); 
                return KAT_HASH_ERROR; 
        } 
        timeTest(2, logFile);   //unit test stop 
        timeTest(3, logFile);   //test stop 
        printf("\tfinished ExtremelyLongMsgKAT for <%d>\n", hashbitlen); 

        fclose(fp_in); 

        return KAT_SUCCESS; 
} 

STATUS_CODES 
genMonteCarlo(int hashbitlen) 
{ 
        char            line[SUBMITTER_INFO_LEN]; 
        BitSequence     Seed[128], Msg[128], MD[64], Temp[128]; 
        int                     i, j, bytelen; 
        FILE            *fp_in; 
        char            logFileName [100]; 
        FILE            *logFile; 

        sprintf(logFileName, "%s_genMonteCarlo_%d.log", ALGORITHM_NAME, hashbitlen); 
        printf("logging results to: %s\n", logFileName); 
        logFile = fopen(logFileName, "w"); 

        if ( (fp_in = fopen("MonteCarlo.txt", "r")) == NULL ) { 
                printf("Couldn't open <MonteCarlo.txt> for read\n"); 
                return KAT_FILE_OPEN_ERROR; 
        } 

        if ( FindMarker(fp_in, "# Algorithm Name:") ) { 
                fscanf(fp_in, "%[^\n]\n", line); 
        } 
        else { 
                printf("genMonteCarlo: Couldn't read Algorithm Name\n"); 
                return KAT_HEADER_ERROR; 
        } 
        if ( FindMarker(fp_in, "# Principal Submitter:") ) { 
                fscanf(fp_in, "%[^\n]\n", line); 
        } 
        else { 
                printf("genMonteCarlo: Couldn't read Principal Submitter\n"); 
                return KAT_HEADER_ERROR; 
        } 

        if ( !ReadHex(fp_in, Seed, 128, "Seed = ") ) { 
                printf("ERROR: unable to read 'Seed' from <MonteCarlo.txt>\n"); 
                return KAT_DATA_ERROR; 
        } 

        bytelen = hashbitlen / 8; 
        memcpy(Msg, Seed, 128); 
        timeTest(0, logFile);   //test start 
        for ( j=0; j<100; j++ ) { 
                for ( i=0; i<1000; i++ ) { 
                        timeTest(1, logFile);   //unit test start 
                        Hash(hashbitlen, Msg, 1024, MD); 
                        timeTest(2, logFile);   //unit test stop 
                        memcpy(Temp, Msg, 128-bytelen); 
                        memcpy(Msg, MD, bytelen); 
                        memcpy(Msg+bytelen, Temp, 128-bytelen); 
                } 
        } 
        timeTest(3, logFile);   //test stop 
        printf("\tfinished MonteCarloKAT for <%d>\n", hashbitlen); 

        fclose(fp_in); 

        return KAT_SUCCESS; 
} 

// 
// ALLOW TO READ HEXADECIMAL ENTRY (KEYS, DATA, TEXT, etc.) 
// 
int 
FindMarker(FILE *infile, const char *marker) 
{ 
        char    line[MAX_MARKER_LEN]; 
        int             i, len; 
 
        len = (int)strlen(marker); 
        if ( len > MAX_MARKER_LEN-1 ) 
                len = MAX_MARKER_LEN-1; 

        for ( i=0; i<len; i++ ) 
                if ( (line[i] = fgetc(infile)) == EOF ) 
                        return 0; 
        line[len] = '\0'; 

        while ( 1 ) { 
                if ( !strncmp(line, marker, len) ) 
                        return 1; 

                for ( i=0; i<len-1; i++ ) 
                        line[i] = line[i+1]; 
                if ( (line[len-1] = fgetc(infile)) == EOF ) 
                        return 0; 
                line[len] = '\0'; 
        } 

        // shouldn't get here 
        return 0; 
} 

// 
// ALLOW TO READ HEXADECIMAL ENTRY (KEYS, DATA, TEXT, etc.) 
// 
int 
ReadHex(FILE *infile, BitSequence *A, int Length, char *str) 
{ 
        int                     i, ch, started; 
        BitSequence     ich; 

        if ( Length == 0 ) { 
                A[0] = 0x00; 
                return 1; 
        } 
        memset(A, 0x00, Length); 
        started = 0; 
        if ( FindMarker(infile, str) ) 
                while ( (ch = fgetc(infile)) != EOF ) { 
                        if ( !isxdigit(ch) ) { 
                                if ( !started ) { 
                                        if ( ch == '\n' ) 
                                                break; 
                                        else 
                                                continue; 
                                } 
                                else 
                                        break; 
                        } 
                        started = 1; 
                        if ( (ch >= '0') && (ch <= '9') ) 
                                ich = ch - '0'; 
                        else if ( (ch >= 'A') && (ch <= 'F') ) 
                                ich = ch - 'A' + 10; 
                        else if ( (ch >= 'a') && (ch <= 'f') ) 
                                ich = ch - 'a' + 10; 

                        for ( i=0; i<Length-1; i++ ) 
                                A[i] = (A[i] << 4) | (A[i+1] >> 4); 
                        A[Length-1] = (A[Length-1] << 4) | ich; 
                } 
        else 
                return 0; 

        return 1; 
} 

void 
fprintBstr(FILE *fp, char *S, BitSequence *A, int L) 
{ 
        int             i; 

        fprintf(fp, "%s", S); 

        for ( i=0; i<L; i++ ) 
                fprintf(fp, "%02X", A[i]); 

        if ( L == 0 ) 
                fprintf(fp, "00"); 

        fprintf(fp, "\n"); 
} 
    
